function Walker(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	if (this.xvel <= 0) {
		this.sprite.goLeft();
		this.xvel = -2;
	} else {
		this.sprite.goRight();
		this.xvel = 2;
	}
	this.lastWalkY = this.y;
};

Walker.prototype = extend(Droid);

Walker.prototype.collideBelow = function(currentBlock) {
	Droid.prototype.collideBelow.call(this, currentBlock);
	this.lastWalkY = this.y;
};

Walker.prototype.collideRight = function(currentBlock) {
	if (this.hasBuff(DroidBuff.CLIMBER)) {
		this.canChangeDirection = false;
		this.setTransform(Climber);
	}
	Droid.prototype.collideRight.call(this, currentBlock);
};

Walker.prototype.collideLeft = function(currentBlock) {
	if (this.hasBuff(DroidBuff.CLIMBER)) {
		this.canChangeDirection = false;
		this.setTransform(Climber);
	}
	Droid.prototype.collideLeft.call(this, currentBlock);
};

Walker.prototype.collideAbove = function(currentBlock) {
	Droid.prototype.collideAbove.call(this, currentBlock);
	this.aboutFace();
};


Walker.prototype.afterCollisions = function() {
	if (Math.abs(this.y - this.lastWalkY) > 5) {
		this.setTransform(Faller);
	}
};

function Digger(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.lastXVel = xvel;
	this.xvel = 0;
	this.sprite.drill();
	this.lastDigY = this.y;
};

Digger.prototype = extend(Droid);

//Digger.prototype.isLegalTransform = function(transform) {
//  return false;
//};

Digger.prototype.collideBelow = function(currentBlock) {
	Droid.prototype.collideBelow.call(this, currentBlock);
	this.lastDigY = this.y;

};

Digger.prototype.afterCollisions = function() {
	var blocksBelow = this.getSurroundingBlocks(0, 0, 0, 5);
	for ( var i = 0; i < blocksBelow.length; i++) {
		var currentBlock = blocksBelow[i];
		this.terrainManager.breakDownMore(currentBlock);
	}
	var blocksBelow = this.getSurroundingBlocks(0, 0, 0, 5);
	for ( var i = 0; i < blocksBelow.length; i++) {
		var currentBlock = blocksBelow[i];
		currentBlock.health -= 5;
		if (currentBlock.health <= 0) {
			this.terrainManager.destroyTerrain(currentBlock);
		}
	}

	if (Math.abs(this.y - this.lastDigY) > 40) {
		this.xvel = this.lastXVel;
		this.setTransform(Faller);
	}
};

function Basher(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.lastBashX = this.x;
	if (this.xvel <= 0) {
		this.sprite.goLeft();
		this.xvel = -1;
	} else {
		this.sprite.goRight();
		this.xvel = 1;
	}
};

Basher.prototype = extend(Droid);

Basher.prototype.collideRight = function(currentBlock) {
	this.x = currentBlock.x - this.width;
	this.lastBashX = this.x;
};

Basher.prototype.collideLeft = function(currentBlock) {
	this.x = currentBlock.x + currentBlock.width;
	this.lastBashX = this.x;
};

Basher.prototype.afterCollisions = function() {
	if (this.xvel <= 0) {
		var blocksBelow = this.getSurroundingBlocks(3, 0, 0, 0);
	} else {
		var blocksBelow = this.getSurroundingBlocks(0, 3, 0, 0);
	}
	for ( var i = 0; i < blocksBelow.length; i++) {
		var currentBlock = blocksBelow[i];
		this.terrainManager.breakDownMore(currentBlock);
	}

	if (this.xvel <= 0) {
		var blocksBelow = this.getSurroundingBlocks(3, 0, 0, 0);
	} else {
		var blocksBelow = this.getSurroundingBlocks(0, 3, 0, 0);
	}
	for ( var i = 0; i < blocksBelow.length; i++) {
		var currentBlock = blocksBelow[i];
		currentBlock.health -= 5;
		if (currentBlock.health <= 0) {
			this.terrainManager.destroyTerrain(currentBlock);
		}
	}

	if (Math.abs(this.x - this.lastBashX) > 20) {
		this.setTransform(Walker);
	}
};

function Faller(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.initialY = this.y;
	if (this.xvel < 0) {
		this.xvel = -1;
		this.sprite.goLeft();
	} else if (this.xvel > 0) {
		this.xvel = 1;
		this.sprite.goRight();
	}
};

Faller.prototype = extend(Droid);

//Digger.prototype.isLegalTransform = function(transform) {
//  return false;
//};

Faller.prototype.collideBelow = function(currentBlock) {
	Droid.prototype.collideBelow.call(this, currentBlock);
	this.setTransform(Walker);
};

Faller.prototype.afterCollisions = function() {
	if (this.hasBuff(DroidBuff.FLOATER) && this.y - this.initialY > 30) {
		this.setTransform(Floater);
	}
};

function Exploder(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
  this.sprite.explode();
	this.timer = 0;
	this.xvel = 0;
};

Exploder.TIME_UNTILL_DEATH = 10;

Exploder.prototype = extend(Droid);

Exploder.prototype.afterCollisions = function() {
	this.timer += 1;
	if (this.timer > Exploder.TIME_UNTILL_DEATH) {
		var blocksAround = this.getSurroundingBlocks(5, 5, 5, 5);
		for ( var i = 0; i < blocksAround.length; i++) {
			var currentBlock = blocksAround[i];
			this.terrainManager.breakDownMore(currentBlock);
		}

		var blocksAround = this.getSurroundingBlocks(5, 5, 5, 5);
		for ( var i = 0; i < blocksAround.length; i++) {
			var currentBlock = blocksAround[i];
			this.terrainManager.destroyTerrain(currentBlock);
		}
		this.setTransform(Dead);
	}
};

Exploder.prototype.isLegalTransform = function(transform) {
	if (transform == Exploder)
		return false;
	return true;
};

function Dead(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.friction = 0.1;
};

Dead.prototype = extend(Droid);

Dead.prototype.isLegalTransform = function(transform) {
	return false;
};

Dead.prototype.isSelectable = function() {
	return false;
};

function Stopper(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.xvel = 0;
	this.lastStopX = this.x;
	this.lastStopY = this.y;
	this.terrain = new Terrain(this.x, this.y, this.width, this.height, null, null, null, null, null, false, Terrain.STATUS_CHAR, true, false);
	world.terrainManager.addTerrain(this.terrain);
};

Stopper.prototype = extend(Droid);

Stopper.prototype.afterCollisions = function() {
	if (this.x != this.lastStopX || this.y != this.lastStopY) {
		this.world.terrainManager.removeTerrain(this.terrain);
		this.terrain.x = this.x;
		this.terrain.y = this.y;
		this.world.terrainManager.addTerrain(this.terrain);
		this.lastStopX = this.x;
		this.lastStopY = this.y;
	}
};

Stopper.prototype.isLegalTransform = function(transform) {
	if (transform != Exploder)
		return false;
	return true;
};

Stopper.prototype.cleanup = function() {
	this.world.terrainManager.removeTerrain(this.terrain);
};

Floater.FLOAT_VELOCITY = 2;

function Floater(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Faller.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
};

Floater.prototype = extend(Faller);

Floater.prototype.afterCollisions = function() {
	if (this.yvel > Floater.FLOAT_VELOCITY)
		this.yvel = Floater.FLOAT_VELOCITY;
};

Climber.RIGHT = 0;
Climber.LEFT = 1;
Climber.VELOCITY = -3;
Climber.TOLLERANCE = 1;

function Climber(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.attached = null;
	if (this.xvel > 0) {
		this.side = Climber.RIGHT;
		this.attached = this.getNearestBlockRight();
	}
	else {
		this.side = Climber.LEFT;
		this.attached = this.getNearestBlockLeft();
	}
	this.origXVel = this.xvel;
	this.xvel = 0;
	this.yvel = Climber.VELOCITY;
	this.canChangeDirection = false;
};

Climber.prototype = extend(Droid);

Climber.prototype.getNearestBlockRight = function() {
	var nearbyBlocks = this.getSurroundingBlocks(0, 5, 0, -1);
	if (nearbyBlocks.length < 0)
		return null;
	
	var min = 0;
	for (var i = 1; i < nearbyBlocks.length; i++) {
		if (nearbyBlocks[i].x < nearbyBlocks[min]) {
			min = i;
		}
	}
	return nearbyBlocks[min];
};

Climber.prototype.getNearestBlockLeft = function() {
	var nearbyBlocks = this.getSurroundingBlocks(5, 0, 0, -1);
	if (nearbyBlocks.length < 0)
		return null;
	
	var max = 0;
	for (var i = 1; i < nearbyBlocks.length; i++) {
		if (nearbyBlocks[i].x < nearbyBlocks[max]) {
			max = i;
		}
	}
	return nearbyBlocks[max];
};

Climber.prototype.collideAbove = function(currentBlock) {
	if (this.side == Climber.LEFT) {
		if (Math.abs(currentBlock.x + currentBlock.width - this.x) < Climber.TOLLERANCE) {
			this.x = currentBlock.x + currentBlock.width;
		}
		else {
			this.xvel = -1 * this.origXVel;
			this.setTransform(Faller);
		}
	}
	else {
		if (Math.abs(currentBlock.x - this.x + this.width) < Climber.TOLLERANCE) {
			this.x = currentBlock.x - this.width;
		}
		else {
			this.xvel = -1 * this.origXVel;
			this.setTransform(Faller);
		}
	}
	Droid.prototype.collideAbove.call(this, currentBlock);
};

Climber.prototype.afterCollisions = function(currentBlock) {
	this.yvel = Climber.VELOCITY;
	if (!this.attached) {
		this.xvel = this.origXVel;
		this.setTransform(Walker);
		return;
	}
	if (this.y + this.height < this.attached.y) {
		this.y = this.attached.y - this.height;
		if (this.side == Climber.RIGHT) {
			this.attached = this.getNearestBlockRight();
			if (this.attached)
				this.x = this.attached.x - this.width;
		}
		else {
			this.attached = this.getNearestBlockLeft();
			if (this.attached)
				this.x = this.attached.x + this.attached.width;
		}
	}
	if (!this.attached) {
		this.xvel = this.origXVel;
		this.setTransform(Walker);
	}
};

Builder.MODE_LAY = 0;
Builder.MODE_WALK = 1;
Builder.VELOCITY = 2;
Builder.BEFORE_LAY_TIME = 20;
Builder.AFTER_LAY_TIME = 20;
Builder.STOP_BEFORE = 4;
Builder.BLOCK_WIDTH = 15;
Builder.BLOCK_HEIGHT = 3;
function Builder(x, y, xvel, yvel, lastX, lastY, buffs, world, sprite) {
	Droid.call(this, x, y, xvel, yvel, lastX, lastY, buffs, world, sprite);
	this.mode = Builder.MODE_WALK;
	this.layed = false;
	this.lastLayed = null;
	if (this.xvel > 0) {
		this.buildXVel = Builder.VELOCITY;
	}
	else {
		this.buildXVel = -1 * Builder.VELOCITY;
	}
	this.switchMode();
};

Builder.prototype = extend(Droid);

Builder.prototype.switchMode = function() {
	if (this.mode == Builder.MODE_LAY) {
		this.mode = Builder.MODE_WALK;
		this.xvel = this.buildXVel;
	}
	else {
		this.mode = Builder.MODE_LAY;
		this.xvel = 0;
		this.layed = false;
	}
	this.timeSinceSwitch = 0;
};

Builder.prototype.layBlock = function() {
	if (this.buildXVel > 0)
		var x = this.x + this.width;
	else
		var x = this.x - Builder.BLOCK_WIDTH;
	var y = this.y + this.height - Builder.BLOCK_HEIGHT;
	var width = Builder.BLOCK_WIDTH;
	var height = Builder.BLOCK_HEIGHT;
	var blocks = this.terrainManager.getTerrain(x, y, width, height);
	if (blocks.length > 0)
		return null;
	var element = document.createElement('div');
	this.world.terrainManager.fallingDiv.appendChild(element);
	element.style.position = 'absolute';
	$(element).offset({ top: y, left: x });
	$(element).width(width);
	$(element).height(height);
	element.style.backgroundColor = 'red';
	var terrain = new Terrain(x, y, width, height, element, x, y, width, height, false, Terrain.STATUS_CHAR, false, false);
	
	this.world.terrainManager.addTerrain(terrain);
	return terrain;
};

Builder.prototype.afterCollisions = function(currentBlock) {
	if (this.mode == Builder.MODE_LAY) {
		if (this.timeSinceSwitch > Builder.BEFORE_LAY_TIME + Builder.AFTER_LAY_TIME) {
			this.switchMode();
		}
		else if (this.timeSinceSwitch > Builder.BEFORE_LAY_TIME && this.layed == false) {
			this.lastLayed = this.layBlock();
			if (!this.lastLayed) {
				this.xvel = this.buildXVel;
				this.setTransform(Walker);
			}
			this.layed = true;
		}
	}
	else {
		if (this.buildXVel > 0) {
			if (this.x + this.width > this.lastLayed.x + this.lastLayed.width - Builder.STOP_BEFORE) {
				this.x = this.lastLayed.x + this.lastLayed.width - Builder.STOP_BEFORE - this.width;
				this.switchMode();
			}
		}
		else {
			if (this.x < this.lastLayed.x + Builder.STOP_BEFORE) {
				this.x = this.lastLayed.x + Builder.STOP_BEFORE;
				this.switchMode();
			}			
		}
	}
	this.timeSinceSwitch++;
};

Builder.prototype.collideAbove = function(currentBlock) {
	Droid.prototype.collideAbove.call(this, currentBlock);
	this.xvel = this.buildXVel;
	this.setTransform(Walker);
};

Builder.prototype.collideLeft = function(currentBlock) {
	Droid.prototype.collideLeft.call(this, currentBlock);
	this.xvel = this.buildXVel;
	this.setTransform(Walker);
};

Builder.prototype.collideRight = function(currentBlock) {
	Droid.prototype.collideRight.call(this, currentBlock);
	this.xvel = this.buildXVel;
	this.setTransform(Walker);
};